#include "tcpTransport.h"
#include <unistd.h>
#include <stdio.h>
#include <sys/select.h>

namespace OmronPlc
{
	tcpTransport::tcpTransport()
	{
	}

	tcpTransport::~tcpTransport()
	{
	}

	void tcpTransport::SetRemote(string ip, uint16_t port)
	{
		_ip = ip;
		_port = port;
	}

	bool tcpTransport::Connect()
	{
		_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
		if (_socket < 0)
		{
			return true;
		}

		_serveraddr.sin_family = AF_INET;
		_serveraddr.sin_addr.s_addr = inet_addr(_ip.c_str());
		_serveraddr.sin_port = htons(_port);

		if (connect(_socket, (struct sockaddr *)&_serveraddr, sizeof(_serveraddr)) < 0)
		{
			return true;
		}

		Connected = true;

		return false;
	}

	void tcpTransport::Close()
	{
		if (Connected)
		{
			close(_socket);
			_socket = 0;
			Connected = false;
		}
	}

	int tcpTransport::Send(const uint8_t command[], int cmdLen)
	{
		if (!Connected)
		{
			return -1;
		}

//		int byteSent = send(_socket, command, cmdLen, MSG_DONTWAIT);
		int bytesSent = send(_socket, command, cmdLen, 0);

		if (bytesSent != cmdLen)
		{
			string msg = "Sending error. (Expected bytes:";
			msg += to_string(cmdLen);
			msg += " Sent: ";
			msg += to_string(bytesSent);
			msg += ")";
			std::cout << msg << std::endl;
			return -1;
		}
		printf("Send Tcp data [%d]: ", cmdLen);
		for(int i=0; i<cmdLen; i++){
			printf("%02x ",command[i]);
		}
		printf("\n");
		return bytesSent;
	}

	int tcpTransport::Receive(uint8_t response[], int respLen)
	{
		if (!Connected)
		{
			return -1;
		}

		// receives the response, this is a synchronous method and can hang the process
		//
		int ret ;
		int cnt = 3;
		int bytesRecv = 0;
		int total = -1;
		while(cnt){
			struct timeval tv = {
				.tv_sec = 0,
				.tv_usec = 100000	//waite for 100ms
			};
			fd_set rfds;

			FD_ZERO(&rfds);
			FD_SET(_socket, &rfds);

			ret = select(_socket + 1, &rfds, NULL, NULL, &tv);
			if(ret < 0){
				perror("select failed ");
				break;
			}else if(ret == 0){
				cnt --;
				continue;
			}
			ret = recv(_socket, response + bytesRecv, 1024 - bytesRecv, 0);
			if(ret <= 0){
				break;
			}
			bytesRecv += ret;
			if(bytesRecv > 8){
				total = (response[4] << 24) + (response[5] << 16) + (response[6] << 8) + response[7] + 8;
				if(total == bytesRecv){
					break;
				}
			}

		}
		// check the number of bytes received
		//
		if (total != bytesRecv)
		{
			string msg = "Receiving error. (Expected:";
			msg += to_string(total);
			msg += " Received: ";
			msg += to_string(bytesRecv);
			msg += ")";
			std::cout << msg << endl;
			return -1;
		}
		printf("Recv Tcp data [%d]: ",total);
		for(int i=0; i<total; i++){
			printf("%02x ",response[i]);
		}
		printf("\n");

		return bytesRecv;
	}
}
